﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Microsoft.TeamFoundation.Client;
using Outlook.WorkItems.Extension.Controls;

namespace Outlook.WorkItems.Extension.Addin.Forms
{
    public partial class InsertWorkItemDataSettingsForm : Form
    {
        public string ServerUri { get; set; }
        private readonly ArrayList workItemFieldsToReturn;
        private QueryDefinition _selectedQuery;

        public WorkItemStore WorkItemStore
        {
            get
            {
                if (_selectedQuery != null)
                    return _selectedQuery.Project.Store;

                return null;
            }
        }

        public Project Project
        {
            get
            {
                return _selectedQuery != null ? _selectedQuery.Project : null;
            }
        }

        public WorkItem SelectedWorkItem
        {
            get
            {
                int[] selectedIds = workItemResultGrid1.GetSelectedIds();
                if (selectedIds != null && selectedIds.Count() > 0)
                {
                    var wi = WorkItemStore.GetWorkItem(selectedIds[0]);
                    return wi;
                }
                return null;
            }
        }

        public IEnumerable<WorkItem> SelectedWorkItems
        {
            get
            {
                int[] selectedIds = workItemResultGrid1.GetSelectedIds();
                if (selectedIds != null && selectedIds.Count() > 0)
                {
                    return selectedIds.Select(item => WorkItemStore.GetWorkItem(item)).ToList();
                }
                return null;
            }
        }

        public bool AttachWorkItemAttachment
        {
            get { return chkAttachWIAttachments.Checked; }
        }

        public IEnumerable<Field> FieldsToInsert
        {
            get { return lbFieldsToInsert.Items.Cast<Field>(); }
        }

        public InsertWorkItemDataSettingsForm()
        {
            InitializeComponent();

            workItemFieldsToReturn = new ArrayList();
            comboTree1.InitCombo();
            comboTree1.NodeSelected += comboTree1_NodeSelected;
            try
            {
                if (!string.IsNullOrEmpty(Properties.Settings.Default.SelectedQuery) && Properties.Settings.Default.SelectedQuery.Contains("#"))
                {
                    string selectedQueryParam = Properties.Settings.Default.SelectedQuery;
                    string[] selectedQueryParams = selectedQueryParam.Split('#');
                    if (selectedQueryParams.Length != 3)
                        return;

                    var serverUri = selectedQueryParams[0];
                    string projectName = selectedQueryParams[1];
                    var queryId = new Guid(selectedQueryParams[2]);
                    ServerUri = serverUri;
                    var tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri(serverUri));
                    var store = tfs.GetService<WorkItemStore>();
                    var p = store.Projects[projectName];

                    var item = p.QueryHierarchy.Find(queryId);

                    if (item != null && item is QueryDefinition)
                    {
                        _selectedQuery = (QueryDefinition)item;
                        var node = comboTree1.m_trvNodes.Nodes.FindNodes(
                            tn => tn is QueryNode && ((QueryNode)tn).TeamQuery.Id == queryId).FirstOrDefault();

                        comboTree1.Text = node != null ? node.FullPath : string.Format("{0}/{1}",tfs.Name,_selectedQuery.Path);

                        IniWorkItemsList();
                    }
                }
            }
            catch { }
        }

        private void btnAdd_Click(object sender, EventArgs e)
        {
            foreach (Field field in lbWIFields.SelectedItems)
            {
                lbFieldsToInsert.Items.Add(field);
            }
            for (int i = lbWIFields.SelectedItems.Count - 1; i >= 0; i--)
            {
                lbWIFields.Items.Remove(lbWIFields.SelectedItems[i]);
            }
            btnOk.Enabled = lbFieldsToInsert.Items.Count > 0;
        }

        private void btnRemove_Click(object sender, EventArgs e)
        {
            foreach (Field field in lbFieldsToInsert.SelectedItems)
            {
                lbWIFields.Items.Add(field);
            }
            for (int i = lbFieldsToInsert.SelectedItems.Count - 1; i >= 0; i--)
            {
                lbFieldsToInsert.Items.Remove(lbFieldsToInsert.SelectedItems[i]);
            }

            btnOk.Enabled = lbFieldsToInsert.Items.Count > 0;
        }

        private void IniWorkItemsList()
        {
            if (_selectedQuery == null)
                return;

            var context = new Hashtable();
            Query query;

            context.Add("project", _selectedQuery.Project.Name);
            GetModifiedStoredQuery(_selectedQuery.QueryText, context);
            query = GetQuery(_selectedQuery.QueryText, context);
            workItemResultGrid1.LoadFromWiql(query.WorkItemStore, query.QueryString);

            var wis = new List<WorkItem>();
            switch (_selectedQuery.QueryType)
            {
                case QueryType.List:
                    var wicol = query.RunQuery();
                    wis.AddRange(wicol.Cast<WorkItem>());
                    break;
                case QueryType.OneHop:
                case QueryType.Tree:
                    var info = query.RunLinkQuery();
                    wis.AddRange(info.Select(item => WorkItemStore.GetWorkItem(item.TargetId)));
                    break;
                default:
                    break;
            }

            InitializeFieldsCollection(wis, query.DisplayFieldList);
        }

        private void InitializeFieldsCollection(List<WorkItem> workItems, DisplayFieldList queryFields)
        {
            try
            {
                var fields = new List<Field>();
                foreach (WorkItem item in workItems)
                {
                    foreach (Field field in item.Fields)
                    {
                        if (!fields.Any(f => f.Name == field.Name))
                            fields.Add(field);
                    }
                }

                fields = fields.OrderBy(f => f.Name).ToList();
                lbWIFields.DisplayMember = "Name";
                lbWIFields.Items.Clear();
                lbFieldsToInsert.Items.Clear();
                foreach (Field field in fields.Where(field => !queryFields.Contains(field.FieldDefinition)))
                {
                    lbWIFields.Items.Add(field);
                }
                foreach (Field field in
                    queryFields.Cast<FieldDefinition>().Select(fieldDefinition => fields.Where(f => f.FieldDefinition.ReferenceName == fieldDefinition.ReferenceName).FirstOrDefault()).Where(field => field != null))
                {
                    lbFieldsToInsert.Items.Add(field);
                }
                btnOk.Enabled = lbFieldsToInsert.Items.Count > 0;
            }
            catch (Exception ex)
            {
                using (var frm = new ErrorForm(ex))
                {
                    frm.ShowDialog();
                }
            }
        }

        private string GetModifiedStoredQuery(string storedQueryText, Hashtable context)
        {
            Query query;
            try
            {
                query = GetQuery(storedQueryText, context);
            }
            catch (Exception)
            {
                return null;
            }
            RemoveUnretrievableFieldsFromArray(workItemFieldsToReturn);
            foreach (string str in workItemFieldsToReturn)
            {
                try
                {
                    FieldDefinition definition = WorkItemStore.FieldDefinitions[str];
                    if ((definition != null) && !query.DisplayFieldList.Contains(definition))
                    {
                        query.DisplayFieldList.Add(definition);
                    }
                    continue;
                }
                catch (ArgumentException)
                {
                    continue;
                }
            }
            return query.QueryString;

        }

        private Query GetQuery(string storedQueryText, Hashtable context)
        {
            return new Query(WorkItemStore, storedQueryText, context);
        }

        private void RemoveUnretrievableFieldsFromArray(ArrayList array)
        {
            var list = new ArrayList();
            var fieldDefinitions = WorkItemStore.FieldDefinitions;
            foreach (string str in array)
            {
                if (fieldDefinitions.Contains(str))
                {
                    if (fieldDefinitions[str].FieldType == FieldType.History)
                        list.Add(str);
                }
                else
                {
                    list.Add(str);
                }
            }
            foreach (string str2 in list)
            {
                array.Remove(str2);
            }
        }

        private void lbWIFields_DoubleClick(object sender, EventArgs e)
        {
            lbFieldsToInsert.Items.Add(lbWIFields.SelectedItems[0]);
            lbWIFields.Items.Remove(lbWIFields.SelectedItems[0]);
            btnOk.Enabled = lbFieldsToInsert.Items.Count > 0;
        }

        private void btnUp_Click(object sender, EventArgs e)
        {
            if (lbFieldsToInsert.Items.Count <= 1 && lbFieldsToInsert.SelectedItems.Count < 1)
                return;

            int firstSelectedIndex = lbFieldsToInsert.SelectedIndices[0];
            int lastSelectedIndex = lbFieldsToInsert.SelectedIndices[lbFieldsToInsert.SelectedIndices.Count - 1];
            if (firstSelectedIndex < 1)
                return;

            var itemToMove = lbFieldsToInsert.Items[firstSelectedIndex - 1];
            lbFieldsToInsert.Items.Remove(itemToMove);
            lbFieldsToInsert.Items.Insert(lastSelectedIndex, itemToMove);
        }

        private void btnDown_Click(object sender, EventArgs e)
        {
            if (lbFieldsToInsert.Items.Count <= 1 && lbFieldsToInsert.SelectedItems.Count <= 0)
                return;

            var firstSelectedIndex = lbFieldsToInsert.SelectedIndices[0];
            var lastSelectedIndex = lbFieldsToInsert.SelectedIndices[lbFieldsToInsert.SelectedIndices.Count - 1];
            if (lastSelectedIndex >= lbFieldsToInsert.Items.Count - 1)
                return;

            var itemToMove = lbFieldsToInsert.Items[lastSelectedIndex + 1];
            lbFieldsToInsert.Items.Remove(itemToMove);
            lbFieldsToInsert.Items.Insert(firstSelectedIndex, itemToMove);
        }

        private void btnOk_Click(object sender, EventArgs e)
        {
            if (_selectedQuery != null)
            {
                string infos = string.Format("{0}#{1}#{2}", ServerUri, Project.Name, _selectedQuery.Id);
                Properties.Settings.Default.SelectedQuery = infos;
                Properties.Settings.Default.Save();
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            using (SelectQueryBox selectQuery = new SelectQueryBox())
            {
                if (selectQuery.ShowDialog() == DialogResult.OK)
                {
                    _selectedQuery = selectQuery.SelectedQuery;
                    ServerUri = selectQuery.TeamServerUri;
                    var node = comboTree1.m_trvNodes.Nodes.FindNodes(
                            tn => tn is QueryNode && ((QueryNode)tn).TeamQuery.Id == _selectedQuery.Id).FirstOrDefault();

                    if (node != null)
                        comboTree1.Text = node.FullPath;
                    IniWorkItemsList();
                }
            }
        }

        private void lbFieldsToInsert_DoubleClick(object sender, EventArgs e)
        {
            lbWIFields.Items.Add(lbFieldsToInsert.SelectedItems[0]);
            lbFieldsToInsert.Items.Remove(lbFieldsToInsert.SelectedItems[0]);
            btnOk.Enabled = lbFieldsToInsert.Items.Count > 0;
        }

        private void comboTree1_DropDown(object sender, EventArgs e)
        {
            comboTree1.ExpandPath();
        }

        void comboTree1_NodeSelected(object sender, TreeViewEventArgs e)
        {
            var node = comboTree1.m_trvNodes.SelectedNode;
            if (node is QueryNode)
            {
                var queryNode = node as QueryNode;
                _selectedQuery = queryNode.TeamQuery;
                ServerUri = queryNode.TeamServerUri;
                IniWorkItemsList();
            }
        }
    }
}
